package com.wjh.interceptor;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.wjh.annotation.AccessLimit;
import com.wjh.common.Constants;
import com.wjh.util.IpUtil;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

/**
 * 访问拦截器
 *
 * @author wenjianhai
 * @date 2023/6/27
 * @since JDK 17
 */
@Slf4j
public class AccessLimitInterceptor implements HandlerInterceptor {

	private RedisTemplate<String, Object> redisTemplate;

	public AccessLimitInterceptor(RedisTemplate<String, Object> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 存储key
		String key = IpUtil.getIpAddress(request) + ":" + request.getContextPath() + ":" + request.getServletPath();

		log.info("访问拦截器处理-开始.key:{}", key);

		try {
			if (handler instanceof HandlerMethod) {
				HandlerMethod handlerMethod = (HandlerMethod) handler;
				// 获取方法
				Method method = handlerMethod.getMethod();
				// 是否有AccessLimit注解
				if (!method.isAnnotationPresent(AccessLimit.class)) {
					return true;
				}
				// 获取注解内容信息
				AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);

				if (accessLimit == null) {
					return true;
				}
				int seconds = accessLimit.second();

				Object rdsObj = redisTemplate.opsForValue().get(key);

				if (rdsObj == null) {
					redisTemplate.opsForValue().set(key, 1, seconds, TimeUnit.SECONDS);
					return true;
				}
				// 已经访问的次数
				Integer count = (Integer) rdsObj;

				log.info("访问拦截器处理.key:{}, 已经访问的次数:{}", key, count);

				if (count.intValue() <= Constants.NUM_ZERO) {
					redisTemplate.opsForValue().set(key, 1, seconds, TimeUnit.SECONDS);
					return true;
				}
				int maxCount = accessLimit.maxCount();

				if (count.intValue() < maxCount) {
					redisTemplate.opsForValue().increment(key);
					return true;
				}
				log.warn("访问拦截器处理,请求过于频繁.key:{}, maxCount:{}, count:{}", key, maxCount, count);

				return false;
			}
			return true;
		} catch (Exception e) {
			log.error(String.format("访问拦截器处理-失败.key:%s", key), e);
			return false;
		}
	}
}
